package com.hancheng.usercloud.business.service.serviceImpl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hancheng.commoncloud.business.entity.enums.DelFlagEnum;
import com.hancheng.commoncloud.business.entity.enums.YesOrNoEnum;
import com.hancheng.commoncloud.business.entity.vo.SysUserVO;
import com.hancheng.commoncloud.framework.contant.Constants;
import com.hancheng.commoncloud.framework.contant.RedisConstants;
import com.hancheng.commoncloud.framework.result.PageResult;
import com.hancheng.commoncloud.framework.util.*;
import com.hancheng.usercloud.business.entity.dto.*;
import com.hancheng.usercloud.business.entity.po.SysUserPO;
import com.hancheng.usercloud.business.entity.vo.UserLoginVO;
import com.hancheng.usercloud.business.entity.vo.UserVO;
import com.hancheng.usercloud.business.service.SysUserService;
import com.hancheng.usercloud.business.mapper.SysUserMapper;
import io.seata.core.context.RootContext;
import ma.glasnost.orika.MapperFacade;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 用户信息表 ServiceImpl
 *
 * @author 韩诚
 * @date 2025/06/22
 */

@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserPO> implements SysUserService {
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private MapperFacade mapperFacade;
    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private DataSource dataSource;

    @PostConstruct
    public void check() {
        System.out.println("当前数据源类型为：" + dataSource.getClass().getName());
    }

    /**
     * 登录
     *
     * @param userLoginDTO
     * @return
     */
    @Override
    public UserLoginVO checkLogin(UserLoginDTO userLoginDTO) {
        SysUserPO sysUserPO = getUserByUserName(userLoginDTO.getUserName());
        ApiAssert.isNotNull(sysUserPO, "用户名或密码错误");
        checkPassword(sysUserPO, userLoginDTO.getPassWord());

        //这里把SysUserPO存入redis中，认证拦截器可以取redis或数据库中的值
        //由于jwt设置的token失效时间为1天，所以这里设置redis的过期时间也为1天
        redisUtils.setCacheObject(String.format(RedisConstants.USER_INFO.getKey(), sysUserPO.getUserId()), mapperFacade.map(sysUserPO, SysUserVO.class), Constants.ONE, TimeUnit.DAYS);
        return getUserLoginVO(sysUserPO);
    }

    /**
     * 用户修改密码
     *
     * @param updateUserPasswordDTO
     */
    @Override
    public void updateUserPassword(UpdateUserPasswordDTO updateUserPasswordDTO) {
        String oldPassword = updateUserPasswordDTO.getOldPassword();
        String newPassword = updateUserPasswordDTO.getNewPassword();
        String confirmPassword = updateUserPasswordDTO.getConfirmPassword();
        //断言两次输入的密码一致，不一致则抛出异常
        ApiAssert.isTrue(StrUtil.equals(newPassword, confirmPassword), "两次输入的新密码不一致");
        Long userId = LocalUserInfoUtil.getAdminUserPO().getUserId();
        SysUserPO sysUserPO = getUserByUserId(userId);
        //断方用户不为空，为空则抛出异常
        ApiAssert.isTrue(ObjectUtil.isNotNull(sysUserPO), "未知的用户");
        //断方旧密码输入正确，否则抛出异常
        boolean passWordFlag = SecurityUtils.matchesPassword(oldPassword, sysUserPO.getPassword());
        ApiAssert.isTrue(passWordFlag, "旧密码输入不正确");
        sysUserPO.setPassword(SecurityUtils.encryptPassword(newPassword));
        sysUserPO.setUpdateTime(new Date());
        sysUserPO.setUpdateUserId(LocalUserInfoUtil.getAdminUserPO().getUserId());
        sysUserMapper.updateById(sysUserPO);
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    @Override
    public UserVO getUserInfo() {
        return mapperFacade.map(LocalUserInfoUtil.getAdminUserPO(), UserVO.class);
    }

    /**
     * 分页查询
     *
     * @param sysUserPageListDTO
     * @return
     */
    @Override
    public PageResult<SysUserVO> getPageList(SysUserPageListDTO sysUserPageListDTO) {
        //获取分页列表
        PageHelper.startPage(sysUserPageListDTO.getPageNo(), sysUserPageListDTO.getPageSize());
        List<SysUserPO> sysUserPOList = sysUserMapper.selectList(new LambdaQueryWrapper<SysUserPO>()
                .eq(ObjectUtil.isNotNull(sysUserPageListDTO.getStatus()), SysUserPO::getStatus, sysUserPageListDTO.getStatus())
                .like(StrUtil.isNotBlank(sysUserPageListDTO.getUserName()), SysUserPO::getUserName, sysUserPageListDTO.getUserName())
                .like(StrUtil.isNotBlank(sysUserPageListDTO.getNickName()), SysUserPO::getNickName, sysUserPageListDTO.getNickName())
                .like(StrUtil.isNotBlank(sysUserPageListDTO.getPhonenumber()), SysUserPO::getPhonenumber, sysUserPageListDTO.getPhonenumber())
                .ge(StrUtil.isNotBlank(sysUserPageListDTO.getStartTime()), SysUserPO::getCreateTime, sysUserPageListDTO.getStartTime())
                .le(StrUtil.isNotBlank(sysUserPageListDTO.getEndTime()), SysUserPO::getCreateTime, sysUserPageListDTO.getEndTime()));

        //返回数据给前端
        PageInfo<SysUserPO> pageInfo = new PageInfo<>(sysUserPOList);
        return new PageResult<>(pageInfo.getTotal(), mapperFacade.mapAsList(sysUserPOList, SysUserVO.class));
    }

    /**
     * 新增用户
     *
     * @param sysUserAddDTO
     */
    @Override
    public void addUser(SysUserAddDTO sysUserAddDTO) {
        //校验用户名称是否唯一
        checkUserNameUnique(sysUserAddDTO.getUserName());
        //如果手机号不为空，则校验手机号码是否唯一
        if (StrUtil.isNotBlank(sysUserAddDTO.getPhonenumber())) {
            checkPhoneUnique(sysUserAddDTO.getPhonenumber(), null);
        }
        //新增用户
        SysUserPO sysUserPO = new SysUserPO();
        BeanUtils.copyProperties(sysUserAddDTO, sysUserPO);
        //密码如果为空，默认为123456
        if (StrUtil.isBlank(sysUserAddDTO.getPassword())) {
            sysUserAddDTO.setPassword("123456");
        }
        sysUserPO.setPassword(SecurityUtils.encryptPassword(sysUserAddDTO.getPassword()));
        sysUserPO.setCreateUserId(LocalUserInfoUtil.getAdminUserPO().getUserId());
        baseMapper.insert(sysUserPO);
    }

    /**
     * 根据用户ID获取用户信息
     *
     * @param userIdDTO
     * @return
     */
    @Override
    public UserVO getUserVOByUserId(UserIdDTO userIdDTO) {
        return mapperFacade.map(sysUserMapper.selectById(userIdDTO.getUserId()), UserVO.class);
    }

    /**
     * 修改用户
     *
     * @param sysUserEditDTO
     */
    @Override
    public void editUser(SysUserEditDTO sysUserEditDTO) {
        //如果手机号不为空，则校验手机号码是否唯一
        if (StrUtil.isNotBlank(sysUserEditDTO.getPhonenumber())) {
            checkPhoneUnique(sysUserEditDTO.getPhonenumber(), sysUserEditDTO.getUserId());
        }
        //校验用户
        SysUserPO user = baseMapper.selectById(sysUserEditDTO.getUserId());
        ApiAssert.isNotNull(user, "未知的用户信息");
        //修改用户
        SysUserPO sysUserPO = new SysUserPO();
        BeanUtils.copyProperties(sysUserEditDTO, sysUserPO);
        sysUserPO.setUpdateUserId(LocalUserInfoUtil.getAdminUserPO().getUserId());
        sysUserPO.setUpdateTime(new Date());
        baseMapper.updateById(sysUserPO);
    }

    /**
     * 删除用户
     *
     * @param userIdDTO
     */
    @Override
    public void deleteUser(UserIdDTO userIdDTO) {
        sysUserMapper.update(null, new LambdaUpdateWrapper<SysUserPO>()
                .eq(SysUserPO::getUserId, userIdDTO.getUserId())
                .set(SysUserPO::getDelFlag, DelFlagEnum.YES.getCode()));
    }

    /**
     * 根据登录名得到用户对象
     *
     * @param userName
     * @return
     */
    @Override
    public SysUserPO getUserByUserName(String userName) {
        return baseMapper.selectOne(new LambdaQueryWrapper<SysUserPO>()
                .eq(SysUserPO::getUserName, userName)
                .eq(SysUserPO::getDelFlag, YesOrNoEnum.NO.getCode())
                .eq(SysUserPO::getStatus, YesOrNoEnum.NO.getCode()));
    }

    /**
     * 验证密码
     *
     * @param sysUserPO
     * @param password
     */
    private void checkPassword(SysUserPO sysUserPO, String password) {
        boolean passWordFlag = SecurityUtils.matchesPassword(password, sysUserPO.getPassword());
        ApiAssert.isTrue(passWordFlag, "用户名或密码错误");
    }

    /**
     * 构建登录返回对象
     *
     * @param sysUserPO
     * @return
     */
    private UserLoginVO getUserLoginVO(SysUserPO sysUserPO) {
        String token = JwtUtil.createToken(sysUserPO.getUserName(), sysUserPO.getPassword(),
                sysUserPO.getUserId());
        return UserLoginVO.builder()
                .userName(sysUserPO.getUserName())
                .nickName(sysUserPO.getNickName())
                .authToken(token).build();
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param userName
     */
    private void checkUserNameUnique(String userName) {
        Integer count = baseMapper.selectCount(new LambdaQueryWrapper<SysUserPO>()
                .eq(SysUserPO::getUserName, userName)
                .eq(SysUserPO::getDelFlag, YesOrNoEnum.NO.getCode()));
        ApiAssert.isTrue(count <= Constants.ZERO, "名称为 【 " + userName + " 】 的登录账号已存在！");
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param phonenumber
     * @param userId
     */
    private void checkPhoneUnique(String phonenumber, Long userId) {
        Integer count = baseMapper.selectCount(new LambdaQueryWrapper<SysUserPO>()
                .eq(SysUserPO::getPhonenumber, phonenumber)
                .eq(SysUserPO::getDelFlag, YesOrNoEnum.NO.getCode())
                .ne(ObjectUtil.isNotNull(userId), SysUserPO::getUserId, userId));
        ApiAssert.isTrue(count <= Constants.ZERO, "手机号已存在！");
    }


    /**
     * 根据用户ID获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public SysUserPO getUserByUserId(Long userId) {
        return baseMapper.selectById(userId);
    }


    /**
     * 新增用户（测试seata）
     *
     * @param userInsertTestDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void insertTest(UserInsertTestDTO userInsertTestDTO) {
        System.out.println("当前 Seata 全局事务ID (XID): " + RootContext.getXID());
        if (StrUtil.isBlank(userInsertTestDTO.getUserName())) {
            ApiAssert.isTrue(false, "新增用户失败！");
        }
        //新增用户
        SysUserPO sysUserPO = new SysUserPO();
        sysUserPO.setUserName(System.currentTimeMillis() + "");
        sysUserPO.setNickName(System.currentTimeMillis() + "");
        //密码如果为空，默认为123456
        userInsertTestDTO.setPassword("123456");

        sysUserPO.setPassword(SecurityUtils.encryptPassword(userInsertTestDTO.getPassword()));
        sysUserPO.setCreateUserId(LocalUserInfoUtil.getAdminUserPO().getUserId());
        baseMapper.insert(sysUserPO);
    }
}
